﻿'TODO: Document LED Gauge
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.ComponentModel
Imports System.ComponentModel.Design

<DefaultEvent("Click"), ToolboxBitmap(GetType(LEDGauge), "LEDGauge.bmp")> _
Public Class LEDGauge
#Region "Defaults"
    Private Const def_SupportTransparency As Boolean = False

    Private def_ForeColor As Color = Color.White

    Private Const def_GaugeLabelPosition As GaugeLabelPositions = GaugeLabelPositions.PositionToLeft
    Private def_GaugeLabelPadding As Integer = 3

    Private Const def_GaugeValue As Double = 75

    Private def_GaugeValuePadding As Integer = 3

    Private Const def_Threshold1_Value As Double = 50
    Private def_Threshold1_Color As Color = Color.Orange
    Private Const def_Threshold2_Value As Double = 65
    Private def_Threshold2_Color As Color = Color.Red
#End Region

#Region "Private Attributes"
    Private _GaugeLabelPosition As GaugeLabelPositions = def_GaugeLabelPosition
    Private _GaugeValue As Double = def_GaugeValue

    Private WithEvents _Background As New BackgroundType(Me)
    Private WithEvents _GaugeValueLabel As GaugeValueLabel
    Private WithEvents _Range As RangeType
    Private WithEvents _LEDStyle As LEDType
    Private WithEvents _Threshold1 As Threshold
    Private WithEvents _Threshold2 As Threshold
#End Region

#Region "Public Enumerations"
    Public Enum GaugeLabelPositions As Integer
        None = 0
        PositionToLeft = 1
        PositionToRight = 2
    End Enum

    
#End Region

#Region "Public Interface"
    Public Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        SetTransparencyMode(False)

        _Threshold1 = New Threshold(def_Threshold1_Value, def_Threshold1_Color)
        _Threshold2 = New Threshold(def_Threshold2_Value, def_Threshold2_Color)
        _GaugeValueLabel = New GaugeValueLabel()
        _Range = New RangeType()
        _LEDStyle = New LEDType()

        Me.ForeColor = def_ForeColor
        Me.Size = New Size(300, 60)
        Me.Padding = New Padding(5, 5, 5, 5)
    End Sub

    Shadows Property Text() As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal value As String)
            MyBase.Text = value
            Me.Invalidate()
        End Set
    End Property
    Shadows Sub ResetText()
        MyBase.Text = Nothing
    End Sub
    Shadows Function ShouldSerializeText() As Boolean
        Return Not (MyBase.Text.Equals(Nothing))
    End Function


    <Category("Appearance"), _
    Description("Text position relative to gauge."), _
    BrowsableAttribute(True)> _
Public Property LabelPosition() As GaugeLabelPositions
        Get
            Return _GaugeLabelPosition
        End Get
        Set(ByVal value As GaugeLabelPositions)
            _GaugeLabelPosition = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetLabelPosition()
        LabelPosition = def_GaugeLabelPosition
    End Sub
    Public Function ShouldSerializeLabelPosition() As Boolean
        Return Not (LabelPosition.Equals(def_GaugeLabelPosition))
    End Function

    <Category("Appearance"), TypeConverter(GetType(BackgroundTypeConverter))> _
    Public Property Background() As BackgroundType
        Get
            Return _Background
        End Get
        Set(ByVal value As BackgroundType)
            _Background = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetBackground()
        _Background.Reset()
    End Sub
    Public Function ShouldSerializeBackground() As Boolean
        Return _Background.ShouldSerialize()
    End Function

    <Category("Gauge"), TypeConverter(GetType(LEDTypeConverter))> _
    Public Property LEDStyle() As LEDType
        Get
            Return _LEDStyle
        End Get
        Set(ByVal value As LEDType)
            _LEDStyle = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetLEDStyle()
        _LEDStyle.Reset()
    End Sub
    Public Function ShouldSerializeLEDStyle() As Boolean
        Return _LEDStyle.ShouldSerialize()
    End Function

    <Category("Gauge"), TypeConverter(GetType(GaugeValueLabelTypeConverter))> _
    Public Property ValueLabel() As GaugeValueLabel
        Get
            Return _GaugeValueLabel
        End Get
        Set(ByVal value As GaugeValueLabel)
            _GaugeValueLabel = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetValueLabel()
        _GaugeValueLabel.Reset()
    End Sub
    Public Function ShouldSerializeValueLabel() As Boolean
        Return _GaugeValueLabel.ShouldSerialize()
    End Function

    <Category("Gauge"), TypeConverter(GetType(RangeTypeConverter))> _
    Public Property Range() As RangeType
        Get
            Return _Range
        End Get
        Set(ByVal value As RangeType)
            _Range = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetRange()
        _Range.Reset()
    End Sub
    Public Function ShouldSerializeRange() As Boolean
        Return _Range.ShouldSerialize()
    End Function

    <Category("Gauge"), _
        Description("The gauge value."), _
        DefaultValue(def_GaugeValue), _
        BrowsableAttribute(True)> _
    Public Property Value() As Double
        Get
            Return _GaugeValue
        End Get
        Set(ByVal value As Double)
            _GaugeValue = value
            Me.Invalidate()
        End Set
    End Property

    <Category("Gauge"), TypeConverter(GetType(ThresholdTypeConverter))> _
    Public Property Threshold1() As Threshold
        Get
            Return _Threshold1
        End Get
        Set(ByVal value As Threshold)
            _Threshold1 = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetThreshold1()
        _Threshold1.Reset()
    End Sub
    Public Function ShouldSerializeThreshold1() As Boolean
        Return _Threshold1.ShouldSerialize()
    End Function

    <Category("Gauge"), TypeConverter(GetType(ThresholdTypeConverter))> _
    Public Property Threshold2() As Threshold
        Get
            Return _Threshold2
        End Get
        Set(ByVal value As Threshold)
            _Threshold2 = value
            Me.Invalidate()
        End Set
    End Property
    Public Sub ResetThreshold2()
        _Threshold2.Reset()
    End Sub
    Public Function ShouldSerializeThreshold2() As Boolean
        Return _Threshold2.ShouldSerialize()
    End Function

#End Region


#Region "Private Methods"
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        'Add your custom paint code here
        Dim G As Graphics = e.Graphics
        G.SmoothingMode = SmoothingMode.HighQuality

        'Determine drawing areas
        Dim ClientRectF As RectangleF
        ClientRectF = New RectangleF(Me.ClientRectangle.Left + Me.Padding.Left, Me.ClientRectangle.Top + Me.Padding.Top, Me.ClientRectangle.Width - Me.Padding.Left - Me.Padding.Right, Me.ClientRectangle.Height - Me.Padding.Top - Me.Padding.Bottom)

        Dim GaugeX As Single = 0
        Dim GaugeY As Single = 0
        Dim GaugeW As Single = 0
        Dim GaugeH As Single = 0

        Dim LabelX As Single = 0
        Dim LabelY As Single = 0
        Dim LabelW As Single = 0
        Dim LabelH As Single = 0

        Dim ValueLabelX As Single = 0
        Dim ValueLabelY As Single = 0
        Dim ValueLabelW As Single = 0
        Dim ValueLabelH As Single = 0


        GaugeY = ClientRectF.Y
        LabelH = G.MeasureString(Me.Text, Me.Font).Height

        If _GaugeLabelPosition <> GaugeLabelPositions.None Then
            LabelW = G.MeasureString(Me.Text, Me.Font).Width
            GaugeW = ClientRectF.Width - LabelW - def_GaugeLabelPadding
        Else
            LabelW = 0
            GaugeW = ClientRectF.Width
        End If
        If _GaugeValueLabel.LabelPosition <> GaugeValueLabel.GaugeValuePositions.None Then
            ValueLabelH = G.MeasureString("1234567890", _GaugeValueLabel.Font).Height
            GaugeH = ClientRectF.Height - ValueLabelH - def_GaugeValuePadding
            ValueLabelY = ClientRectF.Y + GaugeH + def_GaugeLabelPadding
        Else
            ValueLabelH = 0
            GaugeH = ClientRectF.Height
            ValueLabelY = 0
        End If

        Select Case _GaugeLabelPosition
            Case GaugeLabelPositions.PositionToLeft
                LabelX = ClientRectF.X
                GaugeX = LabelX + LabelW + def_GaugeLabelPadding
            Case GaugeLabelPositions.PositionToRight
                GaugeX = ClientRectF.X
                LabelX = GaugeX + GaugeW + def_GaugeLabelPadding
            Case Else
                GaugeX = ClientRectF.X
        End Select

        ValueLabelW = GaugeW
        ValueLabelX = GaugeX

        LabelY = GaugeY + (GaugeH - LabelH) / 2

        Dim GaugeRectF As New RectangleF(GaugeX, GaugeY, GaugeW, GaugeH)
        Dim LabelRectF As New RectangleF(LabelX, LabelY, LabelW, LabelH)
        Dim ValueLabelRectF As New RectangleF(ValueLabelX, ValueLabelY, ValueLabelW, ValueLabelH)


        'Draw Gauge
        DrawGaugeBackground(G, Me.ClientRectangle)

        If _GaugeLabelPosition <> GaugeLabelPositions.None Then DrawGaugeLabel(G, LabelRectF)

        If _GaugeValueLabel.LabelPosition <> GaugeValueLabel.GaugeValuePositions.None Then DrawValueLabel(G, ValueLabelRectF)

        DrawGauge(G, GaugeRectF)
    End Sub

    Private Sub DrawGaugeBackground(ByRef G As Graphics, ByVal Rect As RectangleF)
        If _Background.FillStyle = BackgroundType.FillStyles.Gradient Then
            Dim myBrush As LinearGradientBrush
            myBrush = New LinearGradientBrush(Me.ClientRectangle, _Background.BackColor1, _Background.BackColor2, Me._Background.FillGradientStyle)
            G.FillRectangle(myBrush, Rect)
        Else
            G.FillRectangle(New SolidBrush(Me._Background.BackColor1), Rect)
        End If
    End Sub
    Private Sub DrawGaugeLabel(ByVal G As Graphics, ByVal RectF As RectangleF)
        G.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), RectF)
    End Sub
    Private Sub DrawValueLabel(ByVal G As Graphics, ByVal RectF As RectangleF)
        Select Case _GaugeValueLabel.LabelPosition
            Case GaugeValueLabel.GaugeValuePositions.Left
                G.DrawString(CStr(_GaugeValue), _GaugeValueLabel.Font, New SolidBrush(_GaugeValueLabel.ForeColor), RectF)
            Case GaugeValueLabel.GaugeValuePositions.Center
                Dim LabelW As Single = G.MeasureString(CStr(_GaugeValue), _GaugeValueLabel.Font).Width
                Dim LabelX As Single = RectF.X + (RectF.Width - LabelW) / 2
                G.DrawString(CStr(_GaugeValue), _GaugeValueLabel.Font, New SolidBrush(_GaugeValueLabel.ForeColor), LabelX, RectF.Y)
            Case GaugeValueLabel.GaugeValuePositions.Right
                Dim LabelW As Single = G.MeasureString(CStr(_GaugeValue), _GaugeValueLabel.Font).Width
                Dim LabelX As Single = RectF.X + RectF.Width - LabelW
                G.DrawString(CStr(_GaugeValue), _GaugeValueLabel.Font, New SolidBrush(_GaugeValueLabel.ForeColor), LabelX, RectF.Y)
        End Select
    End Sub
    Private Sub DrawGauge(ByVal G As Graphics, ByVal RectF As RectangleF)
        'G.FillRectangle(Brushes.Red, RectF)

        'Determine width of each rectangular area that will contain LED's based on LED Count and Gap
        Dim LEDW As Single = (RectF.Width - CSng((_LEDStyle.Count - 1) * _LEDStyle.Gap)) / CSng(_LEDStyle.Count)

        Dim LEDX As Single
        For iLED As Integer = 0 To _LEDStyle.Count - 1
            LEDX = RectF.X + CSng(iLED * (LEDW + CSng(_LEDStyle.Gap)))
            DrawLED(G, New RectangleF(LEDX, RectF.Y, LEDW, RectF.Height), LEDColor(iLED))
        Next
    End Sub
    Private Sub DrawLED(ByVal G As Graphics, ByVal RectF As RectangleF, ByVal LEDColor As Color)
        Dim CurrSmoothingMode As SmoothingMode = G.SmoothingMode
        Dim LEDColorLighter As Color = Color.FromArgb(Math.Min(255, LEDColor.R + 220), Math.Min(255, LEDColor.G + 220), Math.Min(255, LEDColor.B + 220))
        Dim LEDColorDarker As Color = Color.FromArgb(Math.Max(0, LEDColor.R - 150), Math.Max(0, LEDColor.G - 150), Math.Max(0, LEDColor.B - 150))
        Dim LEDBrush As LinearGradientBrush
        Dim BoundRectF As RectangleF

        Dim LEDColorBlend As New ColorBlend()
        LEDColorBlend.Colors = New Color() {Color.White, Color.White, LEDColor, LEDColorDarker, LEDColorDarker}
        LEDColorBlend.Positions = New Single() {0, 0.1, 0.6, 0.9, 1}

        G.SmoothingMode = SmoothingMode.HighQuality
        Select Case _LEDStyle.Style
            Case LEDType.LEDStyles.Rectangular
                BoundRectF = RectF
                LEDBrush = New LinearGradientBrush(RectF, Color.White, LEDColor, 25.0!)
                LEDBrush.InterpolationColors = LEDColorBlend
                G.FillRectangle(LEDBrush, BoundRectF)
            Case LEDType.LEDStyles.Square
                BoundRectF = LargestSquare(RectF)
                LEDBrush = New LinearGradientBrush(BoundRectF, Color.White, LEDColor, 25.0!)
                LEDBrush.InterpolationColors = LEDColorBlend
                G.FillRectangle(LEDBrush, BoundRectF)
            Case LEDType.LEDStyles.Elliptical
                BoundRectF = RectF
                LEDBrush = New LinearGradientBrush(RectF, Color.White, LEDColor, 25.0!)
                LEDBrush.InterpolationColors = LEDColorBlend
                G.FillEllipse(LEDBrush, BoundRectF)
            Case LEDType.LEDStyles.Circular
                BoundRectF = LargestSquare(RectF)
                LEDBrush = New LinearGradientBrush(BoundRectF, Color.White, LEDColorDarker, 25.0!)
                LEDBrush.InterpolationColors = LEDColorBlend
                G.FillEllipse(LEDBrush, BoundRectF)
        End Select
        G.SmoothingMode = CurrSmoothingMode
    End Sub

    Private Function LEDColor(ByVal LED As Integer) As Color
        'Determines what color LED should be
        'Note: LED numbering is zero-based.

        Dim LEDRange As Double = (_Range.Max - _Range.Min) / CDbl(_LEDStyle.Count)
        Dim LEDStartValue As Double = _Range.Min + CDbl(LED) * LEDRange
        Dim LEDEndValue As Double = LEDStartValue + LEDRange

        If _GaugeValue >= LEDStartValue Then
            'LED is ON
            'What color should it be
            If LEDStartValue >= _Threshold2.Value Then
                Return _Threshold2.Color
            ElseIf LEDStartValue >= _Threshold1.Value Then
                Return _Threshold1.Color
            Else
                Return _LEDStyle.OnColor
            End If
        Else
            'LED is OFF
            Return _LEDStyle.OffColor
        End If
    End Function
    Private Function LargestSquare(ByVal RectF As RectangleF) As RectangleF
        'Determine largest square area centered within RectF
        Dim Side As Single = Math.Min(RectF.Width, RectF.Height)

        Dim SideX As Single = RectF.X + ((RectF.Width - Side) / 2)
        Dim SideY As Single = RectF.Y + ((RectF.Height - Side) / 2)

        Return New RectangleF(SideX, SideY, Side, Side)
    End Function
#End Region


#Region "Private Event Handlers"
    Private Sub Background_PropertyChanged(ByVal PropertyName As String) Handles _Background.PropertyChanged
        Select Case PropertyName
            Case "BackColor1"
                If Me.Parent Is Nothing Then
                    Me.Refresh()
                Else
                    Me.Parent.Refresh()
                End If
            Case Else
                Me.Invalidate()
        End Select
    End Sub
    Private Sub _Threshold1_PropertyChanged(ByVal PropertyName As String) Handles _Threshold1.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _Threshold2_PropertyChanged(ByVal PropertyName As String) Handles _Threshold2.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _GaugeValueLabel_PropertyChanged(ByVal PropertyName As String) Handles _GaugeValueLabel.PropertyChanged
        Me.Invalidate()
    End Sub
    Private Sub _LEDStyle_PropertyChanged(ByVal PropertyName As String) Handles _LEDStyle.PropertyChanged
        Me.Invalidate()
    End Sub
#End Region

#Region "Transparency Support"
    Private Const WS_EX_TRANSPARENT As Int16 = &H20

    Friend Sub SetTransparencyMode(ByVal IsOn As Boolean)
        If IsOn Then
            'Support transparency - turn off double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, False) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
            Me.SetStyle(ControlStyles.Opaque, True)
        Else
            'No transparency support - enable double-buffering
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) 'Turn double-buffering off for transparency
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
            Me.SetStyle(ControlStyles.Opaque, False)
        End If
        If Me.Parent Is Nothing Then
            Me.Refresh()
        Else
            Me.Parent.Refresh()
        End If
    End Sub
    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or WS_EX_TRANSPARENT
            Return cp
        End Get
    End Property
#End Region

#Region "Hidden Properties"
    <Browsable(False)> _
    Shadows Property BackColor() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property BackgroundImage() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
    <Browsable(False)> _
    Shadows Property BackgroundImageLayout() As Color
        Get
        End Get
        Set(ByVal value As Color)
        End Set
    End Property
#End Region

#Region "Background Type"
    Public Class BackgroundType
        'Defaults
        Private Const def_SupportTransparency As Boolean = False

        Private def_BackColor1 As Color = Color.DarkBlue
        Private def_BackColor2 As Color = Color.DodgerBlue
        Private def_FillStyle As FillStyles = FillStyles.Gradient
        Private def_FillGradientStyle As LinearGradientMode = LinearGradientMode.Horizontal


        'Private Properties
        Private _SupportTransparency As Boolean = def_SupportTransparency

        Private _BackColor1 As Color = def_BackColor1
        Private _BackColor2 As Color = def_BackColor2
        Private _FillStyle As FillStyles = def_FillStyle
        Private _GradientOrientation As LinearGradientMode = def_FillGradientStyle

        Private _ParentCtl As LEDGauge = Nothing


        'Enumerations
        Public Enum FillStyles As Integer
            Solid = 0
            Gradient = 1
        End Enum

        'Public Events
        Public Event PropertyChanged(ByVal PropertyName As String)

        'Public Interface
        Friend Sub New(ByVal Control As LEDGauge)
            _ParentCtl = Control
        End Sub

        ''' <summary>
        ''' Defines the Background color of the gauge when <see cref="FillStyle"/> is set to <see cref="FillStyles">Solid</see>. Otherwise is used as the first color
        ''' in a color gradient with the end color determined by the <see cref="BackColor2"/> property.
        ''' </summary>
        ''' <value>The Background color of the gauge or the start gradient color of background.</value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Description("The background color of the control. Primary color if FillStyle is set to Solid or gradient start color if FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor1() As Color
            Get
                Return _BackColor1
            End Get
            Set(ByVal value As Color)
                _BackColor1 = value
                If _BackColor1 = Color.Transparent AndAlso _FillStyle = FillStyles.Solid Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("BackColor1")
            End Set
        End Property
        ''' <summary>
        ''' Resets the <see>BarGauge.BackColor1</see> property.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub ResetBackColor1()
            BackColor1 = def_BackColor1
        End Sub
        ''' <summary>
        ''' Indicates whether the default value of the property has changed from it's default in design mode and needs to be serialized.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ShouldSerializeBackColor1() As Boolean
            Return Not (BackColor1.Equals(def_BackColor1))
        End Function

        <Description("The secondary color of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property BackColor2() As Color
            Get
                Return _BackColor2
            End Get
            Set(ByVal value As Color)
                _BackColor2 = value
                RaiseEvent PropertyChanged("BackColor2")
            End Set
        End Property
        Public Sub ResetBackColor2()
            BackColor2 = def_BackColor2
        End Sub
        Public Function ShouldSerializeBackColor2() As Boolean
            Return Not (BackColor2.Equals(def_BackColor2))
        End Function

        <Description("The FillStyle for the Background of this control."), _
                BrowsableAttribute(True)> _
        Public Property FillStyle() As FillStyles
            Get
                Return _FillStyle
            End Get
            Set(ByVal value As FillStyles)
                _FillStyle = value
                If _FillStyle = FillStyles.Solid AndAlso _BackColor1 = Color.Transparent Then
                    _ParentCtl.SetTransparencyMode(True)
                Else
                    _ParentCtl.SetTransparencyMode(False)
                End If
                RaiseEvent PropertyChanged("FillStyle")
            End Set
        End Property
        Public Sub ResetFillStyle()
            FillStyle = def_FillStyle
        End Sub
        Public Function ShouldSerializeFillStyle() As Boolean
            Return Not (FillStyle.Equals(def_FillStyle))
        End Function

        <Description("The gradient style of the control background when FillStyle is set to Gradient."), _
            BrowsableAttribute(True)> _
        Public Property FillGradientStyle() As LinearGradientMode
            Get
                Return _GradientOrientation
            End Get
            Set(ByVal value As LinearGradientMode)
                _GradientOrientation = value
                RaiseEvent PropertyChanged("FillGradientStyle")
            End Set
        End Property
        Public Sub ResetFillGradientStyle()
            FillGradientStyle = def_FillGradientStyle
        End Sub
        Public Function ShouldSerializeFillGradientStyle() As Boolean
            Return Not (FillGradientStyle.Equals(def_FillGradientStyle))
        End Function

        Public Sub Reset()
            _BackColor1 = def_BackColor1
            _BackColor2 = def_BackColor2
            _FillStyle = def_FillStyle
            _GradientOrientation = def_FillGradientStyle

            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If _BackColor1.Equals(def_BackColor1) _
                    AndAlso _BackColor2.Equals(def_BackColor2) _
                    AndAlso _FillStyle.Equals(def_FillStyle) _
                    AndAlso _GradientOrientation.Equals(def_FillGradientStyle) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Background)"
        End Function
    End Class
    Public Class BackgroundTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(BackgroundType))
        End Function
    End Class
#End Region

#Region "Threshold"
    Public Class Threshold
        Private def_Value As Double
        Private def_Color As Color

        Private _Value As Double
        Private _Color As Color

        Public Event PropertyChanged(ByVal PropertyName As String)

        Friend Sub New()
            def_Value = Nothing
            def_Color = Nothing
            _Value = Nothing
            _Color = Nothing
        End Sub
        Friend Sub New(ByVal DefaultValue As Double, ByVal DefaultColor As Color)
            def_Value = DefaultValue
            _Value = DefaultValue
            def_Color = DefaultColor
            _Color = DefaultColor
        End Sub

        Public Property Value() As Double
            Get
                Return _Value
            End Get
            Set(ByVal value As Double)
                _Value = value
                RaiseEvent PropertyChanged("Value")
            End Set
        End Property
        Public Sub ResetValue()
            Value = def_Value
        End Sub
        Public Function ShouldSerializeValue() As Boolean
            Return Not (Value.Equals(def_Value))
        End Function

        Public Property Color() As Color
            Get
                Return _Color
            End Get
            Set(ByVal value As Color)
                _Color = value
                RaiseEvent PropertyChanged("Color")
            End Set
        End Property
        Public Sub ResetColor()
            Color = def_Color
        End Sub
        Public Function ShouldSerializeColor() As Boolean
            Return Not (Color.Equals(def_Color))
        End Function

        Public Sub Reset()
            _Value = def_Value
            _Color = def_Color
            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If Value.Equals(def_Value) AndAlso Color.Equals(def_Color) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Threshold)"
        End Function
    End Class
    Public Class ThresholdTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(Threshold))
        End Function
    End Class
#End Region

#Region "GaugeValueLabel"
    Public Class GaugeValueLabel
        Private def_Font As Font = New System.Drawing.Font("Microsoft Sans Serif", 7.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Private def_Color As Color = Color.White
        Private def_Position As GaugeValuePositions = GaugeValuePositions.Center

        Private _Font As Font = def_Font
        Private _Color As Color = def_Color
        Private _Position As GaugeValuePositions = def_Position

        Public Enum GaugeValuePositions As Integer
            None = 0
            Left = 1
            Center = 2
            Right = 3
        End Enum

        Public Event PropertyChanged(ByVal PropertyName As String)

        Friend Sub New()
        End Sub

        Public Property Font() As Font
            Get
                Return _Font
            End Get
            Set(ByVal value As Font)
                _Font = value
                RaiseEvent PropertyChanged("Font")
            End Set
        End Property
        Public Sub ResetFont()
            _Font = def_Font
        End Sub
        Public Function ShouldSerializeFont() As Boolean
            Return Not (Font.Equals(def_Font))
        End Function


        Public Property ForeColor() As Color
            Get
                Return _Color
            End Get
            Set(ByVal value As Color)
                _Color = value
                RaiseEvent PropertyChanged("ForeColor")
            End Set
        End Property
        Public Sub ResetForeColor()
            ForeColor = def_Color
        End Sub
        Public Function ShouldSerializeForeColor() As Boolean
            Return Not (ForeColor.Equals(def_Color))
        End Function

        Public Property LabelPosition() As GaugeValuePositions
            Get
                Return _Position
            End Get
            Set(ByVal value As GaugeValuePositions)
                _Position = value
                RaiseEvent PropertyChanged("LabelPosition")
            End Set
        End Property
        Public Sub ResetLabelPosition()
            _Position = def_Position
        End Sub
        Public Function ShouldSerializeLabelPosition() As Boolean
            Return Not (LabelPosition.Equals(def_Position))
        End Function

        Public Sub Reset()
            _Font = def_Font
            _Color = def_Color
            _Position = def_Position
            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If Font.Equals(def_Font) AndAlso ForeColor.Equals(def_Color) AndAlso LabelPosition.Equals(def_Position) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Value Label)"
        End Function
    End Class
    Public Class GaugeValueLabelTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(GaugeValueLabel))
        End Function
    End Class
#End Region

#Region "RangeType"
    Public Class RangeType
        Private def_Min As Double = 0
        Private def_Max As Double = 100

        Private _Min As Double = def_Min
        Private _Max As Double = def_Max

        Public Event PropertyChanged(ByVal PropertyName As String)

        Friend Sub New()
        End Sub

        Public Property Min() As Double
            Get
                Return _Min
            End Get
            Set(ByVal value As Double)
                _Min = value
                RaiseEvent PropertyChanged("Min")
            End Set
        End Property
        Public Sub ResetMin()
            Min = def_Min
        End Sub
        Public Function ShouldSerializeMin() As Boolean
            Return Not (Min.Equals(def_Min))
        End Function

        Public Property Max() As Double
            Get
                Return _Max
            End Get
            Set(ByVal value As Double)
                _Max = value
                RaiseEvent PropertyChanged("Max")
            End Set
        End Property
        Public Sub ResetMax()
            _Max = def_Max
        End Sub
        Public Function ShouldSerializeMax() As Boolean
            Return Not (Max.Equals(def_Max))
        End Function


        Public Sub Reset()
            _Min = def_Min
            _Max = def_Max
            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If Min.Equals(def_Min) AndAlso Max.Equals(def_Max) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(Range)"
        End Function
    End Class
    Public Class RangeTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(RangeType))
        End Function
    End Class
#End Region

#Region "LEDType"
    Public Class LEDType
        Private def_Count As Integer = 10
        Private def_Gap As Integer = 2
        Private def_Style As LEDStyles = LEDStyles.Circular
        Private def_OnColor As Color = Color.Yellow
        Private def_OffColor As Color = Color.LightGray

        Private _Count As Integer = def_Count
        Private _Gap As Integer = def_Gap
        Private _Style As LEDStyles = def_Style
        Private _OnColor As Color = def_OffColor
        Private _OffColor As Color = def_OnColor


        Public Enum LEDStyles As Integer
            Square = 0
            Rectangular = 1
            Circular = 2
            Elliptical = 3
        End Enum

        Public Event PropertyChanged(ByVal PropertyName As String)

        Friend Sub New()
        End Sub

        Public Property Count() As Integer
            Get
                Return _Count
            End Get
            Set(ByVal value As Integer)
                _Count = value
                RaiseEvent PropertyChanged("Count")
            End Set
        End Property
        Public Sub ResetCount()
            Count = def_Count
        End Sub
        Public Function ShouldSerializeCount() As Boolean
            Return Not (Count.Equals(def_Count))
        End Function

        Public Property Gap() As Integer
            Get
                Return _Gap
            End Get
            Set(ByVal value As Integer)
                _Gap = value
                RaiseEvent PropertyChanged("Gap")
            End Set
        End Property
        Public Sub ResetGap()
            _Gap = def_Gap
        End Sub
        Public Function ShouldSerializeGap() As Boolean
            Return Not (Gap.Equals(def_Gap))
        End Function

        Public Property Style() As LEDStyles
            Get
                Return _Style
            End Get
            Set(ByVal value As LEDStyles)
                _Style = value
                RaiseEvent PropertyChanged("Style")
            End Set
        End Property
        Public Sub ResetStyle()
            Style = def_Style
        End Sub
        Public Function ShouldSerializeStyle() As Boolean
            Return Not (Style.Equals(def_Style))
        End Function

        Public Property OnColor() As Color
            Get
                Return _OnColor
            End Get
            Set(ByVal value As Color)
                _OnColor = value
                RaiseEvent PropertyChanged("OnColor")
            End Set
        End Property
        Public Sub ResetOnColor()
            OnColor = def_OnColor
        End Sub
        Public Function ShouldSerializeOnColor() As Boolean
            Return Not (OnColor.Equals(def_OnColor))
        End Function

        Public Property OffColor() As Color
            Get
                Return _OffColor
            End Get
            Set(ByVal value As Color)
                _OffColor = value
                RaiseEvent PropertyChanged("OffColor")
            End Set
        End Property
        Public Sub ResetOffColor()
            OffColor = def_OffColor
        End Sub
        Public Function ShouldSerializeOffColor() As Boolean
            Return Not (OffColor.Equals(def_OffColor))
        End Function

        Public Sub Reset()
            _Count = def_Count
            _Gap = def_Gap
            _Style = def_Style
            _OnColor = def_OnColor
            _OffColor = def_OffColor
            RaiseEvent PropertyChanged("All")
        End Sub
        Public Function ShouldSerialize() As Boolean
            If Count.Equals(def_Count) AndAlso Gap.Equals(def_Gap) AndAlso Style.Equals(def_Style) AndAlso OnColor.Equals(def_OnColor) AndAlso OffColor.Equals(def_OffColor) Then
                Return False
            Else
                Return True
            End If
        End Function

        Public Overrides Function ToString() As String
            Return "(LED Style)"
        End Function
    End Class
    Public Class LEDTypeConverter
        Inherits TypeConverter

        Public Overrides Function GetPropertiesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True
        End Function
        Public Overrides Function GetProperties(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal value As Object, ByVal attributes() As System.Attribute) As System.ComponentModel.PropertyDescriptorCollection
            Return TypeDescriptor.GetProperties(GetType(LEDType))
        End Function
    End Class
#End Region

End Class
